﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CarbonExchange.Bll
{
    public class UserAuditFactory : FactoryBase<UserAudit>
    {
        protected override void MarkItemForDeletion(UserAudit item)
        {
            throw new NotImplementedException();
        }

        protected override void Validate(IQueryable<UserAudit> items, CarbonExchange.Bll.Exceptions.ValidationException exp)
        {
            throw new NotImplementedException();
        }

        protected override void PopulateDataChanges(UserAudit item, object dataItem)
        {
            throw new NotImplementedException();
        }

        protected override object GetDataItemForUpdate(UserAudit item)
        {
            throw new NotImplementedException();
        }

        internal class JoinHelper
        {
            internal Dal.AcmsUser User { get; set; }
            internal int TotalAudits { get; set; }
            internal int TotalCompletedAudits { get; set; }
            internal DateTime? LastCompletedAudit { get; set; }
        }

        private IQueryable<CarbonExchange.Bll.UserAuditFactory.JoinHelper> GetSelection()
        {
            var tmp = DalContext.AcmsUsers.Join(DalContext.Audits, x => x.Id, y => y.UserId, (x, y) => new { User = x, Audit = y }).GroupBy(x => x.User.Id).Select(x => new JoinHelper() { User = x.First().User, TotalAudits = x.Count(), TotalCompletedAudits = x.Where(y => y.Audit.Completed).Count(), LastCompletedAudit = x.Where(y => y.Audit.Completed).OrderByDescending(y => y.Audit.EndDate).Select(y => y.Audit.EndDate).FirstOrDefault() });
            return tmp;
        }

        private IQueryable<JoinHelper> GetSearchSelection(string name, int siteId)
        {
            IQueryable<JoinHelper> tmp = GetSelection().Where(x => x.User.SiteId == null || x.User.SiteId.Value == siteId);
            if (!string.IsNullOrEmpty(name))
            {
                tmp = tmp.Where(x => string.Concat(x.User.FirstName, " ", x.User.LastName).Contains(name));
            }
            return tmp;
        }

        public int GetTotal(string name, int siteId)
        {
            return GetSearchSelection(name, siteId).Count();
        }

        public IQueryable<UserAudit> Search(string name, int siteId, string sort, int? pageIndex, int? pageSize)
        {
            //get inital sort will be override if sort spefied
            IOrderedQueryable<JoinHelper> tmp = GetSearchSelection(name, siteId).OrderBy(x => x.User.LastName).ThenBy(x => x.User.FirstName);

            var sorts = sort != null ? sort.Split(',').Select(x => x.Trim().ToLower()) : new string[]{};
            bool first = true;
            foreach (var s in sorts)
            {
                var exp = s;
                bool desc = false;
                if (s.EndsWith(" desc"))
                {
                    exp = s.Substring(0, s.Length - 5);
                    desc = true;
                }
                else if(s.EndsWith(" asc"))
                {
                    exp = s.Substring(0, s.Length - 4);
                }
                switch(exp)
                {
                    case "firstname":
                        if(first)
                            tmp = desc ? tmp.OrderByDescending(x => x.User.FirstName) : tmp.OrderBy(x => x.User.FirstName);
                        else
                            tmp = desc ? tmp.ThenByDescending(x => x.User.FirstName) : tmp.ThenBy(x => x.User.FirstName);
                        break;
                    case "lastname":
                        if (first)
                            tmp = desc ? tmp.OrderByDescending(x => x.User.LastName) : tmp.OrderBy(x => x.User.LastName);
                        else
                            tmp = desc ? tmp.ThenByDescending(x => x.User.LastName) : tmp.ThenBy(x => x.User.LastName);
                        break;
                    case "totalaudits":
                        if (first)
                            tmp = desc ? tmp.OrderByDescending(x => x.TotalAudits) : tmp.OrderBy(x => x.TotalAudits);
                        else
                            tmp = desc ? tmp.ThenByDescending(x => x.TotalAudits) : tmp.ThenBy(x => x.TotalAudits);
                        break;
                    case "totalcompletedaudits":
                        if (first)
                            tmp = desc ? tmp.OrderByDescending(x => x.TotalCompletedAudits) : tmp.OrderBy(x => x.TotalCompletedAudits);
                        else
                            tmp = desc ? tmp.ThenByDescending(x => x.TotalCompletedAudits) : tmp.ThenBy(x => x.TotalCompletedAudits);
                        break;
                    case "lastcompletedaudit":
                        if (first)
                            tmp = desc ? tmp.OrderByDescending(x => x.LastCompletedAudit) : tmp.OrderBy(x => x.LastCompletedAudit);
                        else
                            tmp = desc ? tmp.ThenByDescending(x => x.LastCompletedAudit) : tmp.ThenBy(x => x.LastCompletedAudit);
                        break;
                    default:
                        throw new ApplicationException(string.Format("Sort Expression '{0}; not handled. Please Impliment", exp));
                }
                first = false;
            }
            if (pageIndex.HasValue)
            {
                int tmpPageSize = pageSize ?? 10;
                return tmp.Skip(pageIndex.Value * tmpPageSize).Take(tmpPageSize).Convert();
            }
            else
            {
                return tmp.Convert();
            }
        }
    }

    public static class UserAuditConverter
    {
        internal static IQueryable<UserAudit> Convert(this IQueryable<CarbonExchange.Bll.UserAuditFactory.JoinHelper> source)
        {
            return source.Select(x => ConvertItem(x));
        }

        internal static UserAudit Convert(this CarbonExchange.Bll.UserAuditFactory.JoinHelper source)
        {
            return ConvertItem(source);
        }

        private static UserAudit ConvertItem(CarbonExchange.Bll.UserAuditFactory.JoinHelper item)
        {
            if (item != null)
            {
                return new UserAudit()
                {
                    Id = item.User.Id,
                    FirstName = item.User.FirstName,
                    LastName = item.User.LastName,
                    LastCompletedAudit = item.LastCompletedAudit,
                    TotalAudits = item.TotalAudits,
                    TotalCompletedAudits = item.TotalCompletedAudits
                };
            }
            else
            {
                return null;
            }
        }
    }
}
